package com.heima.behavior.service.impl;

import com.heima.behavior.service.BehaviorService;
import com.heima.common.exception.CustomException;
import com.heima.model.behavior.dtos.CollectionBehaviorDto;
import com.heima.model.behavior.dtos.LikesBehaviorDto;
import com.heima.model.behavior.dtos.ReadBehaviorDto;
import com.heima.model.behavior.dtos.UnLikesBehaviorDto;
import com.heima.model.behavior.pojos.*;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.threadlocal.AppThreadLocalUtils;
import com.heima.model.user.pojos.ApUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import java.util.Date;

@Service
@Slf4j
public class BehaviorServiceImpl implements BehaviorService {
    @Autowired
    private MongoTemplate mongoTemplate;

    /**
     * 根据用户id或设备id查询对应的的行为实体
     */
    @Override
    public ApBehaviorEntry findApBehaviorEntryById(Integer uid, Integer eid) {
        //判断数据是否合法
        if (uid == null && eid == null) {
            CustomException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }
        //如果用户id不为空，则使用用户id来向mongodb中查询数据
        if (uid != null) {
            Query query = Query.query(Criteria
                    .where("refId").is(uid)
                    .and("type").is(ApBehaviorEntry.Type.USER.getCode()));
            ApBehaviorEntry behaviorEntry = mongoTemplate.findOne(query, ApBehaviorEntry.class);
            if (behaviorEntry == null) {
                //如果mongo数据库中没有当前behaviorEntry,则新建正在数据库中新建一个
                behaviorEntry = new ApBehaviorEntry();
                behaviorEntry.setCreatedTime(new Date());
                behaviorEntry.setRefId(uid);//设置关联id
                behaviorEntry.setType(ApBehaviorEntry.Type.USER.getCode());//0表示设备，1表示用户
                mongoTemplate.save(behaviorEntry);
            }
            return behaviorEntry;
        }
        //如果用户id为空，则使用设备id来查询
        if (eid != null) {
            Query query = Query.query(Criteria
                    .where("refId").is(eid)
                    .and("type").is(ApBehaviorEntry.Type.EQUIPMENT.getCode()));
            ApBehaviorEntry behaviorEntry = mongoTemplate.findOne(query, ApBehaviorEntry.class);
            if (behaviorEntry == null) {
                behaviorEntry.setType(ApBehaviorEntry.Type.EQUIPMENT.getCode());
                behaviorEntry.setRefId(eid);
                behaviorEntry.setCreatedTime(new Date());
            }
            return behaviorEntry;
        }
        return null;
    }

    /**
     * 点赞或取消点赞
     */
    @Override
    public ResponseResult likesBehavior(LikesBehaviorDto dto) {
        //判断当前用户是否为登录状态
        ApUser apUser = AppThreadLocalUtils.getUser();
        if (apUser == null || apUser.getId() == null) {
            CustomException.cust(AppHttpCodeEnum.NEED_LOGIN, "请先去登录！！");
        }
        Integer uid = apUser.getId();
        //查询实体类
        ApBehaviorEntry apBehaviorEntryById = this.findApBehaviorEntryById(uid, dto.getEquipmentId());
        if (apBehaviorEntryById == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "获取实体信息失败");
        }
        //查询是否存在点赞的信息
        Query query = Query.query(Criteria
                .where("entryId").is(apBehaviorEntryById.getId())
                .and("articleId").is(dto.getArticleId()));
        ApLikesBehavior apLikesBehavior = mongoTemplate.findOne(query, ApLikesBehavior.class);
        if (apLikesBehavior != null && dto.getOperation() == 0) {
            CustomException.cust(AppHttpCodeEnum.DATA_NOT_ALLOW, "你已经点过赞啦！");
        }
        //如果没有点过赞则不能取消点赞
        if (apLikesBehavior == null && dto.getOperation() == 1) {
            CustomException.cust(AppHttpCodeEnum.DATA_NOT_ALLOW, "你还没有点赞呢");
        }
        //执行点赞或取消点赞操作
        if (dto.getOperation() == 0) {
            //点赞
            apLikesBehavior = new ApLikesBehavior();
            apLikesBehavior.setArticleId(dto.getArticleId());
            apLikesBehavior.setCreatedTime(new Date());
            apLikesBehavior.setType((short) 0);
            apLikesBehavior.setOperation((short) 0);
            apLikesBehavior.setEntryId(apBehaviorEntryById.getId());
            mongoTemplate.save(apLikesBehavior);
        } else {
            //取消点赞
            mongoTemplate.remove(query, ApLikesBehavior.class);
        }
        return ResponseResult.okResult();
    }

    /**
     * 保存阅读行为 记录当前用户**查看的次数**，阅读时长，阅读文章的比例，加载的时长
     */
    @Override
    public ResponseResult readBehavior(ReadBehaviorDto dto) {
        //获取当前用户的登录状态
        ApUser user = AppThreadLocalUtils.getUser();
        if (user == null || user.getId() == null) {
            CustomException.cust(AppHttpCodeEnum.NEED_LOGIN, "请先去登录");
        }
        Integer uid = user.getId();
        Integer eid = dto.getEquipmentId();
        //查询数据库中是否存在行为实体类
        ApBehaviorEntry apBehaviorEntryById = this.findApBehaviorEntryById(uid, eid);
        if (apBehaviorEntryById == null) {
            CustomException.cust(AppHttpCodeEnum.DATA_NOT_ALLOW, "当前暂无该实体类");
        }
        //判断数据库中是否存在阅读集合
        Query query = Query.query(Criteria.where("entryId").is(apBehaviorEntryById.getId()).and("articleId").is(dto.getArticleId()));
        ApReadBehavior readBehavior = mongoTemplate.findOne(query, ApReadBehavior.class);
        try {
            if (readBehavior == null) {
                //不存在则新建一个集合，将当前的数据存入
                readBehavior = new ApReadBehavior();
                BeanUtils.copyProperties(readBehavior, dto);
                readBehavior.setEntryId(apBehaviorEntryById.getId());
                readBehavior.setCreatedTime(new Date());
                readBehavior.setUpdatedTime(new Date());
            } else {
                //存在则修改数据即可
                readBehavior.setCount((short) (readBehavior.getCount() + 1));
                readBehavior.setUpdatedTime(new Date());
                readBehavior.setPercentage(dto.getPercentage());
                readBehavior.setReadDuration(readBehavior.getReadDuration() + dto.getReadDuration());
                readBehavior.setLoadDuration(dto.getLoadDuration());
            }
            mongoTemplate.save(readBehavior);
            return ResponseResult.okResult();
        } catch (BeansException e) {
            e.printStackTrace();
            log.info("保存阅读行为时出错，错误原因“{}", e.getMessage());
            return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR, "保存阅读行为时出错");
        }
    }

    /**
     * 保存或取消 不喜欢行为
     */
    @Override
    public ResponseResult unLikesBehavior(UnLikesBehaviorDto dto) {
        //获取当前登录用户
        ApUser user = AppThreadLocalUtils.getUser();
        if (user == null || user.getId() == null) {
            CustomException.cust(AppHttpCodeEnum.NEED_LOGIN);
        }
        Integer uid = user.getId();
        Long articleId = dto.getArticleId();
        //判断数据库中有无当前行为形体类
        ApBehaviorEntry apBehaviorEntryById = findApBehaviorEntryById(uid, dto.getEquipmentId());
        if (apBehaviorEntryById == null) {
            CustomException.cust(AppHttpCodeEnum.DATA_NOT_EXIST, "暂无当前实体类！");
        }
        //判断数据库中是否有保存或取消不喜欢行为实体类
        Query query = Query.query(Criteria
                .where("entryId").is(apBehaviorEntryById.getId())
                .and("articleId").is(articleId));
        ApUnlikesBehavior behavior = mongoTemplate.findOne(query, ApUnlikesBehavior.class);
        //不能对自己操作
        if (behavior != null && dto.getType().intValue() == 0) {
            CustomException.cust(AppHttpCodeEnum.DATA_NOT_ALLOW, "你已经设置过不喜欢！");
        }
        if (dto.getType().intValue() == 0) {
            //设置不喜欢行为
            behavior = new ApUnlikesBehavior();
            behavior.setArticleId(articleId);
            behavior.setCreatedTime(new Date());
            behavior.setEntryId(apBehaviorEntryById.getId());
            behavior.setType((short) 0);
            mongoTemplate.save(behavior);
        } else {
            //取消不喜欢行为
            mongoTemplate.remove(query, ApUnlikesBehavior.class);
        }
        return ResponseResult.okResult();
    }

    /**
     * 保存或取消 收藏行为
     */
    @Override
    public ResponseResult collectionBehavior(CollectionBehaviorDto dto) {
        //判断当前用户是否登录
        ApUser user = AppThreadLocalUtils.getUser();
        if (user == null || user.getId() == null) {
            CustomException.cust(AppHttpCodeEnum.NEED_LOGIN);
        }
        Integer entryId = user.getId();
        Integer eid = dto.getEquipmentId();
        //判断有无当前的行为实体
        ApBehaviorEntry apBehaviorEntry = findApBehaviorEntryById(entryId, eid);
        if (apBehaviorEntry == null) {
            CustomException.cust(AppHttpCodeEnum.DATA_NOT_EXIST, "暂无当前行为实体！！！");
        }
        //查询保存或取消 收藏行为
        Query query = Query.query(Criteria
                .where("entryId").is(apBehaviorEntry.getId())
                .and("articleId").is(dto.getArticleId())
                .and("type").is(dto.getType()));
        ApCollection apCollection = mongoTemplate.findOne(query, ApCollection.class);
        //不能重复收藏
        if (apCollection != null && dto.getOperation() == 0) {
            CustomException.cust(AppHttpCodeEnum.DATA_NOT_ALLOW, "你已经收藏过啦！");
        }
        if (apCollection == null && dto.getOperation() == 1) {
            CustomException.cust(AppHttpCodeEnum.DATA_NOT_ALLOW, "你还没有收藏过呢");
        }
        if (dto.getOperation() == 0) {
            //执行收藏操作
            apCollection = new ApCollection();
            apCollection.setArticleId(dto.getArticleId());
            apCollection.setCollectionTime(new Date());
            apCollection.setEntryId(apBehaviorEntry.getId());
            apCollection.setType(dto.getType());
            mongoTemplate.save(apBehaviorEntry);
        } else {
            //取消收藏
            mongoTemplate.remove(query, ApCollection.class);
        }
        return ResponseResult.okResult();
    }
}
